package com.zy.gpdemo.service;

import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;

import javax.annotation.Resource;

import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.yc.utils.files.PropertiesUtil;
import com.zy.gpdemo.dao.HsqldbDao;
import com.zy.gpdemo.domain.BasePrintTaskData;
import com.zy.gpdemo.domain.PrintTask;
import com.zy.gpdemo.domain.Printer;
import com.zy.gpdemo.utils.HttpApi;

@Service
public class PrinterService {
	public static final List<Printer> printers = new ArrayList<>();	// 所有的打印机实例
	public static List<String> allWarehouse = new ArrayList<>();	// 所有的平台编码
	public static List<String> allPrinterIp = new ArrayList<>();	// 所有的打印机IP
	public static List<String> allStockCode = new ArrayList<>();	// 所有的任务区间编码
	private String warehouses;
	private String printerIp;
	private String updateDataTime;	// 更新打印任务的时间(单位:s)
	private String appRoot;
	private String stockCode;
	private static String iotUrl;	// 物联网平台数据上传接口
	@Resource
	public HsqldbDao hsqldbTest;
	private boolean lock = true;
	private boolean tag = true;

	public PrinterService() {
		// 初始化所有打印机
		init();
	}

	/**
	 * 1. 初始化printer对象
	 * 2. 加载内置数据库未打印任务
	 * 3. 定时检测打印机状态并更新打印任务
	 * 4. 定时删除7天前的打印任务
	 */
	private void init() {
		// 加载配置文件
		// Eclipse运行:config文件夹位于根目录下
		// JAR包或者WAR包运行:config文件夹位于同级目录下
		warehouses = PropertiesUtil.getPropertiesKey("config/application.properties", "autoPrint.warehouse");
		printerIp = PropertiesUtil.getPropertiesKey("config/application.properties", "autoPrint.printerIp");
		updateDataTime = PropertiesUtil.getPropertiesKey("config/application.properties", "autoPrint.updateDataTime");
		appRoot = PropertiesUtil.getPropertiesKey("config/application.properties", "autoPrint.appRoot");
		stockCode = PropertiesUtil.getPropertiesKey("config/application.properties", "autoPrint.stockCode");
		iotUrl = PropertiesUtil.getPropertiesKey("config/application.properties", "autoPrint.iotUrl");
		for(String warehouse :warehouses.split(",")) {
			allWarehouse.add(warehouse);
		}
		for(String ip :printerIp.split(",")) {
			allPrinterIp.add(ip);
		}
		for(String code :stockCode.split(",")) {
			allStockCode.add(code);
		}
		String[] appRoots = appRoot.split(",");
		int i = 0;
		// 初始化打印实例
		for (; i < allWarehouse.size() && i < appRoots.length && i < allPrinterIp.size() && i<allStockCode.size(); i++) {
			printers.add(new Printer(allPrinterIp.get(i), allWarehouse.get(i), appRoots[i], allStockCode.get(i)));
		}
		// 删除多余的打印机IP信息
		while(allPrinterIp.size() > i) {
			allPrinterIp.remove(allPrinterIp.size()-1);
		}
		// 加载内置数据库任务队列
		new Thread(() -> {
			lock = false;
			try {
				// 等待hsqldbDao自动装载
				Thread.sleep(5000L);
				// 注入hsqldbDao对象到printer实例中
				initPrinter();
				for (Printer printer : printers) {
					// 程序上次退出后尚未执行的等待打印任务
					List<PrintTask> tasks = hsqldbTest.findTask(0, printer.getName(), printer.getStockCode());
					// 程序上次退出后尚未执行的正在打印任务
					tasks.addAll(hsqldbTest.findTask(1, printer.getName(),printer.getStockCode()));
					for (PrintTask task : tasks) {
						printer.getAwaitTask().add(task);
					}
					// webSocket推送
					sendMessage(1, printer.getIp(), JSON.parseObject(JSON.toJSONString(printer)));
				}
			} catch (InterruptedException e) {
				e.printStackTrace();
			} finally {
				lock = true;
			}

		}).start();

		// 定时器，检测打印机各种状态并读取数据库更新打印任务
		new Timer(true).schedule(new TimerTask() {

			public void run() {
				// 等待数据库数据被加载结束
				if (lock) {
					try {
						// 依次更新打印机等待打印的数据
						for (Printer printer : printers) {
							// 获取当前库区的拣货单数据
							List<BasePrintTaskData> data = HttpApi.getPrintTasks(printer.getAppRoot(),
									printer.getStockCode(), printer.getIp(), printer.getName());
							// 将获取的拣货单数据追加到等待打印的任务队列里面
							for (BasePrintTaskData taskData : data) {
								PrintTask task = new PrintTask(
										taskData.getMessageId() != 0L ? String.valueOf(taskData.getMessageId())
												: taskData.getMessageIds(),
										taskData.getWarehouseCode(), taskData.getStockCode(), 0,
										new Timestamp(System.currentTimeMillis()), taskData.getAppRoot(),
										taskData.getReportName(), taskData.getReportParams(), taskData.getPrintNums());
								hsqldbTest.insertTask(task);
								printer.getAwaitTask().add(task);
							}
							// 刷新前端展示，异步发送，不影响其他任务执行
							sendMessage(1, printer.getIp(), JSON.parseObject(JSON.toJSONString(printer)));
						}
					} catch (Exception e) {
						System.out.println("---------数据库更新打印任务异常---------");
					}
				}
			}
		}, 0L, Integer.parseInt(updateDataTime) * 1000L);

		// 定时器，12小时清理一次内置数据库
		new Timer(true).schedule(new TimerTask() {

			public void run() {
				try {
					SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
					Calendar calendar = Calendar.getInstance();
					calendar.add(Calendar.DAY_OF_MONTH, -6);
					hsqldbTest.deleteHistory(simpleDateFormat.format(calendar.getTime()));
				} catch (Exception e) {
					System.out.println("----------数据库清理数据库异常-------");
				}
			}

		}, 5000L, 12 * 60 * 60 * 1000L);
	}

	/**
	 * 启动所有的打印机打印任务
	 * 
	 * @return true
	 */
	public boolean startAllPrinter() {

		for (Printer printer : printers) {
			if (printer.check() && !printer.getEsc().getStatus().isOffLine()) {
				printer.start();
			}
		}
		return true;
	}

	/**
	 * 通过IP启动打印机打印任务
	 * 
	 * @param ip
	 * @return boolean
	 */
	public boolean startPrinterByIP(String ip) {
		for (Printer printer : printers) {
			if (printer.getIp().equals(ip)) {
				printer.start();
				return true;
			}
		}
		return false;
	}

	/**
	 * 终止打印机打印任务
	 */
	public void stopAllPrinter() {
		for (Printer printer : printers) {
			printer.stop();
		}
	}

	/**
	 * 通过IP关闭打印机
	 * 
	 * @param ip
	 * @return
	 */
	public boolean stopPrinterByIP(String ip) {
		for (Printer printer : printers) {
			if (printer.getIp().equals(ip)) {
				printer.stop();
				return true;
			}
		}
		return false;
	}

	/**
	 * 初始化打印机的hsqldbDao对象
	 * 
	 * @return boolean
	 */
	public boolean initPrinter() {
		if (tag) {
			for (Printer printer : printers) {
				printer.init(hsqldbTest);
			}
			tag = false;
			return true;
		} else {
			return false;
		}
	}

	/**
	 * 重新打印
	 * 
	 * @param ip
	 * @param msgid
	 * @return boolean
	 */
	public boolean rePrintByIP(String ip, String msgid) {
		for (Printer printer : printers) {
			if (printer.getIp().equals(ip)) {
				return printer.rePrint(msgid);
			}
		}
		return false;
	}

	/**
	 * 获取所有打印机状态信息，如果部分打印机离线将会增加延迟时间
	 * @return	打印机状态(JSON)
	 */
	public String getAllStatus() {
		return JSON.toJSONString(printers);
	}

	public String getStatusByIP(String ip) {
		for (Printer printer : printers) {
			if (printer.getIp().equals(ip)) {
				return JSON.toJSONString(printer);
			}
		}
		return null;
	}

	/**
	 * ip2 打印 ip1任务
	 * 
	 * @param ip1
	 * @param ip2
	 * @return boolean
	 */
	public boolean addIP(String ip1, String ip2) {
		Printer printer1 = null, printer2 = null;

		for (Printer printer : printers) {
			if (printer.getIp().equals(ip1)) {
				printer1 = printer;
			} else if (printer.getIp().equals(ip2)) {
				printer2 = printer;
			}
		}
		if (printer1 != null && printer2 != null) {
			printer2.addOther(printer1.getAwaitTask());
			printer2.getOtherIp().add(ip1);
			sendMessage(1, printer2.getIp(), JSON.parseObject(JSON.toJSONString(printer2)));
			return true;
		} else {
			return false;
		}
	}

	/**
	 * IP2不再执行IP1的打印任务
	 * 
	 * @param ip1
	 * @param ip2
	 * @return boolean
	 */
	public boolean remove(String ip1, String ip2) {
		Printer printer1 = null, printer2 = null;
		for (Printer printer : printers) {
			if (printer.getIp().equals(ip1)) {
				printer1 = printer;
			} else if (printer.getIp().equals(ip2)) {
				printer2 = printer;
			}
		}
		if (printer1 != null && printer2 != null) {
			printer2.removeOther(printer1.getAwaitTask());
			printer2.getOtherIp().remove(ip1);
			sendMessage(1, printer2.getIp(), JSON.parseObject(JSON.toJSONString(printer2)));
			return true;
		} else {
			return false;
		}
	}
	
	/**
	 * 	消息推送
	 * @param code
	 * @param ip
	 * @param message
	 */
	public static void sendMessage(int code, String ip, JSONObject object) {
		// webSocket推送至前端展示页面
		WebSocketService.sendMessage(code, ip, object.toJSONString());
		// Http推送至物联网平台
		Map<String,Object> data = new HashMap<>();
		JSONObject status = object.getJSONObject("esc").getJSONObject("status");
		data.put("state", object.getBoolean("offline") == true ? "OFFLINE" : (status.getBoolean("offLine") == true ? "FAULT":"ONLINE"));
		data.put("organization", object.getString("name") + "-" + object.getString("stockCode"));
		data.put("identfy", object.getString("ip"));
		data.put("ipAddress", object.getString("ip"));
		data.put("deviceName", "热敏打印机");
		String describes = status.getBoolean("cover")==true ? "上盖故障," : "";
		describes += status.getBoolean("cutter")==true ? "切刀故障," : "";
		describes += status.getBoolean("temperatureAndVoltage")==true ? "打印头故障," : "";
		describes += status.getBoolean("paperDo")==true ? "纸张用尽," : "";
		if(describes.length()!=0) {
			describes.substring(0,describes.length() - 1);
		}
		data.put("describes", describes);
		HttpApi.post(iotUrl, data);
	}
	
	/**
	 * 更新错误次数
	 * @param appRoot
	 * @param printTaskId
	 * @param failMsg
	 */
	public static void updateFailTimes(String appRoot,Long printTaskId, String failMsg) {
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("INTERFACE_TYPE", "UPDATE_FAIL_TIMES");
        paramMap.put("printTaskId", printTaskId);
        paramMap.put("failMsg", failMsg);
        HttpApi.post(appRoot, paramMap);
    }
}
